package v5_customize_metadata_tag

import (
	"context"
	"fmt"
	"go-demo/orm/interval/errs"
	"strings"
)

// Selector 上面实现 From where 等 select 语句的方法，最终通过实现 build 方法 构建出Query对象
// Selector 还需要实现 Querier 接口
// 而 Querier接口上面 只定义最终的方法(Get、GetMulti)
// 最终的调用形式就是：NewSelector().From(...).Where(...).Order(...).....build().(Get(ctx)/GetMulti(ctx))
// NewSelector().From(...).Where(...).Order(...).....build() 用于构造 SQL; .(Get(ctx)/GetMulti(ctx)) 用于将结果转换成结构体
type Selector[T any] struct {
	sb    strings.Builder
	table string
	where []Predicate
	args  []any
	model *model
	db    *DB
}

func (s *Selector[T]) Get(ctx context.Context) (*T, error) {
	//TODO implement me
	panic("implement me")
}

func (s *Selector[T]) GetMulti(ctx context.Context) ([]*T, error) {
	//TODO implement me
	panic("implement me")
}

func (s *Selector[T]) From(table string) *Selector[T] {
	s.table = table
	return s
}

// Where 可以传多个谓词，多个谓词之间用 and 连接
func (s *Selector[T]) Where(ps ...Predicate) *Selector[T] {
	s.where = ps
	return s
}

func (s *Selector[T]) Build() (*Query, error) {
	var err error
	// 先获取元数据
	s.model, err = s.db.registry.get(new(T))
	if err != nil {
		return nil, err
	}
	if err := s.buildFrom(); err != nil { // 构造 from 子句
		return nil, err
	}
	if err := s.buildWhere(); err != nil { // 构造 where 子句
		return nil, err
	}
	s.sb.WriteByte(';')
	return &Query{
		SQL:  s.sb.String(),
		Args: s.args,
	}, nil

}

func (s *Selector[T]) buildFrom() error {
	s.sb.WriteString("SELECT * FROM ")
	if s.table == "" {
		s.sb.WriteByte('`')
		s.sb.WriteString(s.model.tableName)
		s.sb.WriteByte('`')
	} else {
		s.sb.WriteString(s.table)
	}
	return nil
}

func (s *Selector[T]) buildWhere() error {
	if len(s.where) > 0 {
		s.sb.WriteString(" WHERE ")
		// 先将所传的 Predicate 都用 and 连接起来
		p := s.where[0]
		for i := 1; i < len(s.where); i++ {
			p = p.And(s.where[i])
		}
		if err := s.buildExpression(p); err != nil {
			return err
		}
	}
	return nil
}

func (s *Selector[T]) buildExpression(e Expression) error {
	if e == nil {
		return nil
	}

	switch expr := e.(type) { // 根据表达式的具体类型进行处理
	//case nil:
	case value:
		s.sb.WriteByte('?')
		s.args = append(s.args, expr.val)
	case Column: // 代表是列名，先和元数据进行校验，然后拼接
		fd, ok := s.model.fieldMap[expr.name]
		if !ok {
			return errs.NewErrUnknownField(expr.name)
		}
		s.sb.WriteString("`" + fd.colName + "`")
	case Predicate:
		// 如果左边是一个Predicate，那么加上括号;然后递归构造左边
		// 构造操作符
		// 如果右边是一个Predicate，那么加上括号然后递归构造右边
		_, ok := expr.left.(Predicate)
		if ok {
			s.sb.WriteByte('(')
		}
		if err := s.buildExpression(expr.left); err != nil {
			return err
		}
		if ok {
			s.sb.WriteByte(')')
		}
		// 处理操作符
		s.sb.WriteString(" " + expr.op.String() + " ")
		// 递归处理右边的表达式
		_, ok = expr.right.(Predicate)
		if ok {
			s.sb.WriteByte('(')
		}
		if err := s.buildExpression(expr.right); err != nil {
			return err
		}
		if ok {
			s.sb.WriteByte(')')
		}
	default:
		return fmt.Errorf("orm: 不支持的表达式 %v", expr)
	}
	return nil
}

func NewSelector[T any](db *DB) *Selector[T] {
	return &Selector[T]{
		db: db,
	}
}
